package cn.t.facade.user;


import cn.t.constants.CommonConstants;
import cn.t.converter.user.RoleInfoDTOConverter;
import cn.t.core.exception.BizException;
import cn.t.core.facade.FacadeImpl;
import cn.t.core.mode.PageInfoDTO;
import cn.t.core.mode.PageQueryDTO;
import cn.t.core.mode.SortedParamDTO;
import cn.t.dto.user.ResourceInfoDTO;
import cn.t.dto.user.RoleInfoDTO;
import cn.t.core.enums.base.CommonError;
import cn.t.enums.user.RoleTypeEnum;
import cn.t.enums.user.UpdateEventTypeEnum;
import cn.t.model.user.CustomerFirmDO;
import cn.t.model.user.ParticipantInfoDO;
import cn.t.model.user.ParticipantRoleDO;
import cn.t.model.user.RoleDeviceDO;
import cn.t.model.user.RoleFirmDO;
import cn.t.model.user.RoleInfoDO;
import cn.t.model.user.RoleSkuDO;
import cn.t.model.user.UserInfoDO;
import cn.t.service.user.CustomerFirmService;
import cn.t.service.user.ParticipantRoleService;
import cn.t.service.user.RoleDeviceService;
import cn.t.service.user.RoleFirmService;
import cn.t.service.user.RoleInfoService;
import cn.t.service.user.RoleSkuService;
import cn.t.service.user.UserInfoService;
import cn.t.user.event.UserQueryUpdateEvent;
import cn.t.user.event.UserRedisClearEvent;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static cn.t.constants.Constants.REDIS_KEY__ROLE_INFO;


/**
 * 角色信息表服务编排
 *
 * @author l
 */
@Slf4j
@Service
@AllArgsConstructor
public class RoleInfoFacade extends FacadeImpl<RoleInfoDTO, RoleInfoDO, RoleInfoDTOConverter, RoleInfoService> {


    @Transactional
    @Override
    public boolean add(RoleInfoDTO roleInfoDTO) {
        if (StringUtils.isNotBlank(roleInfoDTO.getRoleCode())) {
            List<RoleInfoDO> exists = service.findByCode(roleInfoDTO.getRoleCode());
            if (!CollectionUtils.isEmpty(exists)) {
                throw new BizException(CommonError.ILLEGAL_PARAMETER, "存在重复的角色编码");
            }
        }

        if (RoleTypeEnum.SYSTEM.getCode().equals(roleInfoDTO.getRoleType()) && CollectionUtils.isEmpty(roleInfoDTO.getFirmIds())) {
            CustomerFirmDO customerFirmDO = customerFirmService.getCustomerUser();
            if (customerFirmDO != null) {
                roleInfoDTO.setFirmIds(Collections.singletonList(customerFirmDO.getId()));
            }
        }

        Long roleId = service.addAndReturnId(converter.dto2Model(roleInfoDTO));


        return roleFirmFacade.update(roleId, roleInfoDTO.getFirmIds());
    }

    @Transactional
    @Override
    public boolean update(RoleInfoDTO roleInfoDTO) {

        if (StringUtils.isNotBlank(roleInfoDTO.getRoleCode())) {
            List<RoleInfoDO> exists = service.findByCode(roleInfoDTO.getRoleCode());
            if (!CollectionUtils.isEmpty(exists)) {
                for (RoleInfoDO roleInfo : exists) {
                    if (!roleInfo.getId().equals(roleInfoDTO.getId())) {
                        throw new BizException(CommonError.ILLEGAL_PARAMETER, "存在重复的角色编码");
                    }
                }
            }
        }

        if (RoleTypeEnum.SYSTEM.getCode().equals(roleInfoDTO.getRoleType()) && CollectionUtils.isEmpty(roleInfoDTO.getFirmIds())) {
            CustomerFirmDO customerFirmDO = customerFirmService.getCustomerUser();
            if (customerFirmDO != null) {
                roleInfoDTO.setFirmIds(Collections.singletonList(customerFirmDO.getId()));
            }
        }
        boolean result = super.update(roleInfoDTO);
        result = roleFirmFacade.update(roleInfoDTO.getId(), roleInfoDTO.getFirmIds());

        applicationEventPublisher.publishEvent(new UserRedisClearEvent(String.format(REDIS_KEY__ROLE_INFO, roleInfoDTO.getId()), String.format(REDIS_KEY__ROLE_INFO, roleInfoDTO.getId())));

        return result;
    }


    @Transactional
    public void assignRights(RoleInfoDTO roleInfoDTO, List<ResourceInfoDTO> resourceInfoDtoList) {
        RoleInfoDO roleInfo = service.fullFill(converter.dto2Model(roleInfoDTO));

        this.modifyRoleInfo(roleInfoDTO, roleInfo);

        roleResourceFacade.assignRights(roleInfoDTO.getId(), resourceInfoDtoList);

        applicationEventPublisher.publishEvent(new UserRedisClearEvent(String.format(REDIS_KEY__ROLE_INFO, roleInfoDTO.getId()), String.format(REDIS_KEY__ROLE_INFO, roleInfoDTO.getId())));
    }

    @Override
    public boolean remove(Long roleId) {
        List<ParticipantRoleDO> participantRoleList = participantRoleService.findByRoleId(roleId);
        if (!CollectionUtils.isEmpty(participantRoleList)) {
            throw new BizException(CommonError.ILLEGAL_PARAMETER, "指定的角色下存在用户，无法删除！");
        }

        List<RoleSkuDO> roleSkuList = roleSkuService.findByRoleId(roleId);
        if (!CollectionUtils.isEmpty(roleSkuList)) {
            throw new BizException(CommonError.ILLEGAL_PARAMETER, "指定的角色下绑定过物料，无法删除！");
        }

        List<RoleDeviceDO> roleDeviceList = roleDeviceService.findByRoleId(roleId);
        if (!CollectionUtils.isEmpty(roleDeviceList)) {
            throw new BizException(CommonError.ILLEGAL_PARAMETER, "指定的角色下绑定过设备，无法删除！");
        }

        List<RoleFirmDO> roleFirmList = roleFirmService.findByRoleId(roleId);
        if (!CollectionUtils.isEmpty(roleFirmList)) {
            roleFirmService.removeByRoleId(roleId);
        }


        boolean result = service.removeById(roleId);
        applicationEventPublisher.publishEvent(new UserRedisClearEvent(String.format(REDIS_KEY__ROLE_INFO, roleId), String.format(REDIS_KEY__ROLE_INFO, roleId)));

        return result;
    }

    @Override
    public List<RoleInfoDTO> queryList(RoleInfoDTO dto, int start, Integer pageSize, String field, String direction) {
        List<RoleInfoDTO> result = super.queryList(dto, start, pageSize, field, direction);

        if (CollectionUtils.isEmpty(result)) {
            return result;
        }

        Set<Long> roleIds = result.stream().map(RoleInfoDTO::getId).collect(Collectors.toSet());
        List<RoleFirmDO> roleFirmList = roleFirmService.findByRoleIds(roleIds);
        if (CollectionUtils.isEmpty(roleFirmList)) {
            return result;
        }
        // 使用Java 8 Stream API来转换
        Map<Long, List<Long>> roleFirmMap = roleFirmList.stream()
                .collect(Collectors.groupingBy(RoleFirmDO::getRoleId,
                        Collectors.mapping(RoleFirmDO::getFirmId, Collectors.toList())));

        if (roleFirmMap.isEmpty()) {
            return result;
        }

        for (RoleInfoDTO roleInfoDTO : result) {
            roleInfoDTO.setFirmIds(roleFirmMap.get(roleInfoDTO.getId()));
        }

        return result;

    }

    public RoleInfoDTO findById(Long roleId) {
        return converter.model2Dto(service.findById(roleId));
    }


    public List<RoleInfoDTO> findAnonymousRoleByParticipantId(Long participantId) {
        List<RoleInfoDO> list = service.findAnonymousRoleByParticipantId(participantId);
        return list.stream().map(converter::model2Dto).collect(Collectors.toList());

    }


    public void deleteRoleById(Long roleId) {
        service.deleteRoleById(roleId);
    }


    private void modifyRoleInfo(RoleInfoDTO newRoleInfo, RoleInfoDO oldRoleInfo) {
        boolean needToModify = false;

        RoleInfoDTO modifiedDto = new RoleInfoDTO();

        if (StringUtils.isNotBlank(newRoleInfo.getRoleName()) && !newRoleInfo.getRoleName().equals(oldRoleInfo.getRoleName())) {
            modifiedDto.setRoleName(newRoleInfo.getRoleName());
            needToModify = true;
        }
        modifiedDto.setId(newRoleInfo.getId());

        if (needToModify) {
            service.update(converter.dto2Model(modifiedDto));
        }
    }


    @Transactional
    public Boolean assignParticipants(Long roleId, List<Long> userIds) {

        userIds = new ArrayList<>(new HashSet<>(userIds));

        RoleInfoDO roleInfo = new RoleInfoDO();
        roleInfo.setId(roleId);
        roleInfo = service.fullFill(roleInfo);

        List<ParticipantRoleDO> exists = participantRoleService.findByRoleId(roleId);
        if (!CollectionUtils.isEmpty(exists)) {
            for (ParticipantRoleDO pr : exists) {
                if (CollectionUtils.isEmpty(userIds) || !userIds.contains(pr.getUserId())) {
                    participantRoleService.removeById(pr.getId());
                }
            }
        }

        for (Long userId : userIds) {
            UserInfoDO userInfoDO = userInfoService.findById(userId);
            if (userInfoDO == null) {
                String errorMessage = String.format("指定的用户不存在 userId=%s ", userId);
                log.error(errorMessage);
                throw new BizException(CommonError.ILLEGAL_PARAMETER, errorMessage);
            }

            // key = firmId
            Map<Long, ParticipantInfoDO> firmMap = new HashMap<>();
            participantRoleService.addRole(userInfoDO, roleInfo, firmMap);
        }

        for (Long userId : userIds) {
            applicationEventPublisher.publishEvent(new UserQueryUpdateEvent(userId, userSessionFacade.operatorInfo(), userId, UpdateEventTypeEnum.UPDATE, UpdateEventTypeEnum.UPDATE, UpdateEventTypeEnum.UPDATE));
        }

        if (!CollectionUtils.isEmpty(exists)) {
            for (ParticipantRoleDO pr : exists) {
                if (CollectionUtils.isEmpty(userIds) || !userIds.contains(pr.getUserId())) {
                    applicationEventPublisher.publishEvent(new UserQueryUpdateEvent(pr.getUserId(), userSessionFacade.operatorInfo(), pr.getUserId(), UpdateEventTypeEnum.UPDATE, UpdateEventTypeEnum.UPDATE, UpdateEventTypeEnum.UPDATE));
                }
            }
        }


        return true;
    }

    public PageInfoDTO<RoleInfoDTO> entRolePage(PageQueryDTO<RoleInfoDTO> queryDTO) {
        SortedParamDTO sortedParamDTO = queryDTO.getSortParam();
        RoleInfoDTO queryParam = queryDTO.getParam();
        if (queryParam.getFirmId() == null) {
            return new PageInfoDTO<>(queryDTO.getPageNo(), queryDTO.getPageSize(), CommonConstants.ZERO, Collections.emptyList());
        }
        // 查询公司下的角色
        List<RoleFirmDO> roleFirms = this.roleFirmService.list(queryParam.getFirmId());
        if (CollectionUtils.isEmpty(roleFirms)) {
            return new PageInfoDTO<>(queryDTO.getPageNo(), queryDTO.getPageSize(), CommonConstants.ZERO, Collections.emptyList());
        }

        List<Long> roleIds = roleFirms.stream().map(RoleFirmDO::getRoleId).collect(Collectors.toList());
        queryParam.setRoleIds(roleIds);
        List<RoleInfoDTO> list = this.queryList(queryParam, queryDTO.getStart(), queryDTO.getPageSize(), sortedParamDTO.getField(), sortedParamDTO.getDirection());
        if (CollectionUtils.isEmpty(list)) {
            return new PageInfoDTO<>(queryDTO.getPageNo(), queryDTO.getPageSize(), 0L, null);
        } else {
            long total = queryDTO.getTotal();
            if (queryDTO.isNotNeedPageQuery()) {
                total = this.count(queryParam);
            }

            return new PageInfoDTO<>(queryDTO.getPageNo(), queryDTO.getPageSize(), total, list);
        }
    }

    // 查询角色下对应的用户
    public List<Long> getRoleUsers(Long roleId) {
        List<ParticipantRoleDO> participantRoles = this.participantRoleService.findByRoleId(roleId);
        return participantRoles.stream().map(ParticipantRoleDO::getUserId).collect(Collectors.toList());
    }

    @Autowired
    private UserSessionFacade userSessionFacade;

    @Autowired
    private RoleResourceFacade roleResourceFacade;

    @Autowired
    private RoleFirmFacade roleFirmFacade;

    @Autowired
    private ParticipantRoleService participantRoleService;

    @Autowired
    private RoleFirmService roleFirmService;

    @Autowired
    private RoleSkuService roleSkuService;

    @Autowired
    private RoleDeviceService roleDeviceService;

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @Autowired
    private UserInfoService userInfoService;


    @Autowired
    private CustomerFirmService customerFirmService;

}

